package com.bstek.ureport.console.designer;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;

import com.bstek.ureport.cache.CacheUtils;
import com.bstek.ureport.console.RenderPageServletAction;
import com.bstek.ureport.console.cache.TempObjectCache;
import com.bstek.ureport.console.exception.ReportDesignException;
import com.bstek.ureport.definition.ReportDefinition;
import com.bstek.ureport.dsl.ReportParserLexer;
import com.bstek.ureport.dsl.ReportParserParser;
import com.bstek.ureport.export.ReportRender;
import com.bstek.ureport.expression.ErrorInfo;
import com.bstek.ureport.expression.ScriptErrorListener;
import com.bstek.ureport.parser.ReportParser;
import com.bstek.ureport.provider.report.ReportProvider;
import com.bstek.ureport.utils.UreportDBConnectionPoolUtils;

public class DesignerServletAction
  extends RenderPageServletAction
{
  private ReportRender reportRender;
  private ReportParser reportParser;
  private List<ReportProvider> reportProviders = new ArrayList<ReportProvider>();
  
  public void execute(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    String method = retriveMethod(req);
    if (method != null)
    {
      invokeMethod(method, req, resp);
    }
    else
    {
      VelocityContext context = new VelocityContext();
      Object attribute = req.getAttribute("ctx");
      context.put("contextPath", attribute);
      resp.setContentType("text/html");
      resp.setCharacterEncoding("utf-8");
      Template template = this.ve.getTemplate("ureport-html/designer.html", "utf-8");
      PrintWriter writer = resp.getWriter();
      template.merge(context, writer);
      writer.close();
    }
  }
  
  public void scriptValidation(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    String content = req.getParameter("content");
    ANTLRInputStream antlrInputStream = new ANTLRInputStream(content);
    ReportParserLexer lexer = new ReportParserLexer(antlrInputStream);
    CommonTokenStream tokenStream = new CommonTokenStream(lexer);
    ReportParserParser parser = new ReportParserParser(tokenStream);
    ScriptErrorListener errorListener = new ScriptErrorListener();
    parser.removeErrorListeners();
    parser.addErrorListener(errorListener);
    parser.expression();
    List<ErrorInfo> infos = errorListener.getInfos();
    writeObjectToJson(resp, infos);
  }
  
  public void conditionScriptValidation(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    String content = req.getParameter("content");
    ANTLRInputStream antlrInputStream = new ANTLRInputStream(content);
    ReportParserLexer lexer = new ReportParserLexer(antlrInputStream);
    CommonTokenStream tokenStream = new CommonTokenStream(lexer);
    ReportParserParser parser = new ReportParserParser(tokenStream);
    ScriptErrorListener errorListener = new ScriptErrorListener();
    parser.removeErrorListeners();
    parser.addErrorListener(errorListener);
    parser.expr();
    List<ErrorInfo> infos = errorListener.getInfos();
    writeObjectToJson(resp, infos);
  }
  
  public void parseDatasetName(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    String expr = req.getParameter("expr");
    ANTLRInputStream antlrInputStream = new ANTLRInputStream(expr);
    ReportParserLexer lexer = new ReportParserLexer(antlrInputStream);
    CommonTokenStream tokenStream = new CommonTokenStream(lexer);
    ReportParserParser parser = new ReportParserParser(tokenStream);
    parser.removeErrorListeners();
    ReportParserParser.DatasetContext ctx = parser.dataset();
    String datasetName = ctx.Identifier().getText();
    Map<String, String> result = new HashMap<String, String>();
    result.put("datasetName", datasetName);
    writeObjectToJson(resp, result);
  }
  
  public void savePreviewData(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    String content = req.getParameter("content");
    InputStream inputStream = IOUtils.toInputStream(content, "utf-8");
    ReportDefinition reportDef = this.reportParser.parse(inputStream, "p");
    this.reportRender.rebuildReportDefinition(reportDef);
    IOUtils.closeQuietly(inputStream);
    TempObjectCache.putObject("p", reportDef);
  }
  
  public void loadReport(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    String file = req.getParameter("file");
    if (file == null) {
      throw new ReportDesignException("Report file can not be null.");
    }
    file = ReportUtils.decodeFileName(file);
    Object obj = TempObjectCache.getObject(file);
    if ((obj != null) && ((obj instanceof ReportDefinition)))
    {
      ReportDefinition reportDef = (ReportDefinition)obj;
      TempObjectCache.removeObject(file);
      writeObjectToJson(resp, new ReportDefinitionWrapper(reportDef));
    }
    else
    {
      ReportDefinition reportDef = this.reportRender.parseReport(file,req);
      writeObjectToJson(resp, new ReportDefinitionWrapper(reportDef));
    }
  }
  
  public void deleteReportFile(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    String file = req.getParameter("file");
    if (file == null) {
      throw new ReportDesignException("Report file can not be null.");
    }
    ReportProvider targetReportProvider = null;
    for (ReportProvider provider : this.reportProviders) {
      if (file.startsWith(provider.getPrefix()))
      {
        targetReportProvider = provider;
        break;
      }
    }
    if (targetReportProvider == null) {
      throw new ReportDesignException("File [" + file + "] not found available report provider.");
    }
    targetReportProvider.deleteReport(file, req);
  }
  
  public void saveReportFile(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException, ClassNotFoundException, SQLException
  {
	    String file = req.getParameter("file");
	    String fenleiName=req.getParameter("fenleiName");
	    String fenlei = req.getParameter("fenlei");
	    file = ReportUtils.decodeFileName(file);
	    String content = req.getParameter("content");
	    ReportProvider targetReportProvider = null;
	    for (ReportProvider provider : this.reportProviders) {
	      if (file.startsWith(provider.getPrefix()))
	      {
	        targetReportProvider = provider;
	        break;
	      }
	    }
//	    String username = ConfigPropUtil.getProperty("jdbc.username");
//	    String password = ConfigPropUtil.getProperty("jdbc.password");
//	    String driver = ConfigPropUtil.getProperty("jdbc.driver");
//	    String url = ConfigPropUtil.getProperty("jdbc.url");
	    Statement stmt = null;
		Object attribute = req.getAttribute("ctx");
		String serverName = null;
		if(attribute instanceof String) {
			serverName = ((String)(null != attribute && !"".equals(attribute) ? attribute : "")).startsWith("/") ? ((String)attribute).substring(1) : ((String)attribute);
		}
	    
	    Connection conn=null;
//		Class.forName(driver);
//		conn=DriverManager.getConnection(url, username, password);
	//	
//		Object attribute = req.getAttribute("ctx");
//		String id = ((String)(null != attribute && !"".equals(attribute) ? attribute : "")).startsWith("/") ? ((String)attribute).substring(1) : ((String)attribute);
//		String sqlStr = "SELECT id, dbdriver, dbip, dbname, dbport, dbpwd, dbuser FROM pt_dbinfo WHERE active = ? AND ismain = ? AND id = ?;";
//		PreparedStatement statement = conn.prepareStatement(sqlStr);
//		statement.setInt(1, 1);
//		statement.setInt(2, 1);
//		statement.setString(3, id);
//		ResultSet resultSet = statement.executeQuery();
//		if(resultSet.next()) {
//			username = resultSet.getString("dbuser");
//			password = resultSet.getString("dbpwd");
//			driver = resultSet.getString("dbdriver");
//			url = "jdbc:mysql://"
//					+ resultSet.getString("dbip") 
//					+ ":"
//					+ resultSet.getString("dbport")
//					+ "/"
//					+ resultSet.getString("dbname")
//					+ "?characterEncoding=UTF-8&useSSL=false&createDatabaseIfNotExist=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";
//			
//			conn.close();
//			
//		}
//		Class.forName(driver);
//		conn=DriverManager.getConnection(url, username, password);
	    
	    conn = UreportDBConnectionPoolUtils.getConnection(serverName);
	     
	    stmt = conn.createStatement();
	    String selectSql="SELECT COUNT(id) id from rp_report_fenlei  where name='"+file+"'" ;
	    ResultSet obj=stmt.executeQuery(selectSql);
	    int rowCount = 0;    
	    if(obj.next()) {    
	      rowCount=obj .getInt("id");    
	    } 
	    if(rowCount==0) {
	    	   String sql = " INSERT INTO `rp_report_fenlei` (`id`, `name`, `type`,remark)  VALUES (uuid(),'" + 
	    			      file + "','" + fenlei + "','"+fenleiName+"')";
	    			    stmt.executeUpdate(sql);
	    }
	    if (targetReportProvider == null) {
	      throw new ReportDesignException("File [" + file + "] not found available report provider.");
	    }
	    targetReportProvider.saveReport(file, content, req);
	    InputStream inputStream = IOUtils.toInputStream(content, "utf-8");
	    ReportDefinition reportDef = this.reportParser.parse(inputStream, file);
	    this.reportRender.rebuildReportDefinition(reportDef);
	    CacheUtils.cacheReportDefinition(file, reportDef);
	    IOUtils.closeQuietly(inputStream);
	  }
  
  public void loadReportProviders(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
	synchronized (this.reportProviders) {
		for (ReportProvider p : this.reportProviders) {
			p.updateReportFiles(req);
		}
		writeObjectToJson(resp, this.reportProviders);
	}
  }
  
  public void setReportRender(ReportRender reportRender)
  {
    this.reportRender = reportRender;
  }
  
  public void setReportParser(ReportParser reportParser)
  {
    this.reportParser = reportParser;
  }
  
  public void setApplicationContext(ApplicationContext applicationContext)
    throws BeansException
  {
    super.setApplicationContext(applicationContext);
    Collection<ReportProvider> providers = applicationContext.getBeansOfType(ReportProvider.class).values();
    for (ReportProvider provider : providers) {
      if ((!provider.disabled()) && (provider.getName() != null)) {
        this.reportProviders.add(provider);
      }
    }
  }
  
  public String url()
  {
    return "/designer";
  }
}
